/*
 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
 */
#include <stdint.h>

#include "k_types.h"
#include "errno.h"
#include "fsl_lpi2c.h"
#include "aos/hal/i2c.h"
#include "aos/kernel.h"

#define AOS_PORT_I2C1 1
#define AOS_BASE_I2C1 LPI2C1

#define LPI2C_CLOCK_SOURCE_DIVIDER (5U)

#define I2C_CLOCK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U))
#define I2C_BAUDRATE   100000U

static aos_mutex_t i2c_mux;
static inline uint32_t get_i2c_base(uint8_t port)
{
    uint32_t base = 0;

    switch (port) {
        case AOS_PORT_I2C1:
            base = (uint32_t)AOS_BASE_I2C1;
            break;

        default:
            return 0;
    }

    return base;
}

void I2C1_Init(void)
{
    lpi2c_master_config_t masterConfig = {0};

    LPI2C_MasterGetDefaultConfig(&masterConfig);

    masterConfig.baudRate_Hz = I2C_BAUDRATE;

    LPI2C_MasterInit(AOS_BASE_I2C1, &masterConfig, I2C_CLOCK_FREQ);
}

void I2C1_DeInit(void)
{
    LPI2C_MasterDeinit(AOS_BASE_I2C1);
}

int32_t hal_i2c_init(i2c_dev_t *i2c)
{
    static int init_flag=0;
    int32_t ret = -1;

    if (i2c == NULL) {
       return -1;
    }

    switch (i2c->port) {
        case AOS_PORT_I2C1:
            if(init_flag==0){
                aos_mutex_new(&i2c_mux);
                init_flag=1;
            }
            I2C1_Init();
            ret = 0;
            break;

        default:
            break;
    }

    return ret;
}


int32_t hal_i2c_master_send(i2c_dev_t *i2c, uint16_t dev_addr, const uint8_t *data,
                            uint16_t size, uint32_t timeout)
{
    int ret = -1;

    return ret;
}

int32_t hal_i2c_master_recv(i2c_dev_t *i2c, uint16_t dev_addr, uint8_t *data,
                            uint16_t size, uint32_t timeout)
{
    int ret = -1;

    return ret;
}

int32_t hal_i2c_slave_send(i2c_dev_t *i2c, const uint8_t *data, uint16_t size, uint32_t timeout)
{
    int ret = -1;

    return ret;
}

int32_t hal_i2c_slave_recv(i2c_dev_t *i2c, uint8_t *data, uint16_t size, uint32_t timeout)
{
    int ret = -1;
    return ret;
}

int32_t hal_i2c_mem_write(i2c_dev_t *i2c, uint16_t dev_addr, uint16_t mem_addr,
                          uint16_t mem_addr_size, const uint8_t *data, uint16_t size,
                          uint32_t timeout)
{
    int ret = -1;
    uint32_t base = 0;
    lpi2c_master_transfer_t xfer;

    if (NULL == i2c || NULL == data){
        return ret;
    }
    base = get_i2c_base(i2c->port);
    if (base == 0) {
        return ret;
    }
    if(aos_mutex_lock(&i2c_mux,100)!=0){
        return -1;
    }

    xfer.slaveAddress = dev_addr;
    xfer.direction = kLPI2C_Write;
    xfer.subaddress = (uint32_t)mem_addr;
    xfer.subaddressSize = (size_t)mem_addr_size;
    xfer.data = (void *)data;
    xfer.dataSize = (size_t)size;
    xfer.flags = kLPI2C_TransferDefaultFlag;

    ret = (int)LPI2C_MasterTransferBlocking((LPI2C_Type *)base, &xfer);
    aos_mutex_unlock(&i2c_mux);
    return ret;
};

int32_t hal_i2c_mem_read(i2c_dev_t *i2c, uint16_t dev_addr, uint16_t mem_addr,
                         uint16_t mem_addr_size, uint8_t *data, uint16_t size,
                         uint32_t timeout)
{
    int ret = -1;
    uint32_t base = 0;
    lpi2c_master_transfer_t masterXfer = {0};

    if (NULL == i2c || NULL == data){
        return ret;
    }
    base = get_i2c_base(i2c->port);
    if (base == 0) {
        return ret;
    }
    if(aos_mutex_lock(&i2c_mux,100)!=0){
        return -1;
    }

    masterXfer.slaveAddress = dev_addr;
    masterXfer.direction = kLPI2C_Read;
    masterXfer.subaddress = (uint32_t)mem_addr;;
    masterXfer.subaddressSize = (size_t)mem_addr_size;
    masterXfer.data = (void *)data;
    masterXfer.dataSize = (size_t)size;
    masterXfer.flags = kLPI2C_TransferDefaultFlag;

    ret = (int)LPI2C_MasterTransferBlocking((LPI2C_Type *)base, &masterXfer);
    aos_mutex_unlock(&i2c_mux);
    return ret;
};

int32_t hal_i2c_finalize(i2c_dev_t *i2c)
{
    int32_t ret = -1;

    if (i2c == NULL) {
        return -1;
    }

    switch (i2c->port) {
        case AOS_PORT_I2C1:
            aos_mutex_free(&i2c_mux);
            I2C1_DeInit();
            ret = 0;
            break;
        default:
            break;
    }

    return ret;
}

